// xp_dumpdata.cpp
// ---------------
// Extended stored procedure DLL for returning SQL connection information.

#include "xp_dumpdata.h"

BOOL APIENTRY DllMain(HMODULE hModule,DWORD  ul_reason_for_call,LPVOID lpReserved)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}

// Versioning export
__declspec(dllexport) ULONG __GetXpVersion()
{
   return ODS_VERSION;
}

// Xsproc entry point
__declspec(dllexport) SRVRETCODE xp_dumpdata(SRV_PROC *srvproc)
{
	SRVRETCODE	vRetCode;

	// Call the function and return
	vRetCode = SqlDumpData(srvproc);

	return(vRetCode);
}

// Send a SQL msg (non-error)
SRVRETCODE Sql_SendMsg(SRV_PROC *srvproc,TCHAR* tczMsg)
{
	int	iResult = 0;
	// Both the ASCII and UNICODE calls are assuming a NULL terminated string
#ifdef UNICODE
	// wcslen() is used here because 'SRV_NULLTERM' seems to always result in FAILURE with srv_wsendmsg()
	iResult = srv_wsendmsg(srvproc,(DBTINYINT)0,(DBTINYINT)0,tczMsg,wcslen(tczMsg));//SRV_NULLTERM);
#else
	iResult = srv_sendmsg(srvproc, SRV_MSG_INFO, 0,(DBTINYINT)0,(DBTINYINT)0,NULL,0,0,tczMsg,strlen((CHAR*)tczMsg));
#endif
	if(iResult != SUCCEED)
		return(Sql_SendErr(srvproc,_T("Sql_SendMsg failure.")));
	return(SUCCEED);
}

// Send a SQL msg (error)
SRVRETCODE Sql_SendErr(SRV_PROC *srvproc,TCHAR* tczErr)
{
	int	iResult = 0;
	// Both the ASCII and UNICODE calls are assuming a NULL terminated string
#ifdef UNICODE
	// wcslen() is used here because 'SRV_NULLTERM' seems to always result in FAILURE with srv_wsendmsg()
	iResult = srv_wsendmsg(srvproc,0,SRV_MSG_ERROR,tczErr,wcslen(tczErr));//SRV_NULLTERM);
#else
	iResult = srv_sendmsg(srvproc, SRV_MSG_ERROR, 0,(DBTINYINT)0,(DBTINYINT)0,NULL,0,0,tczErr,strlen((CHAR*)tczErr));
#endif
	if(SUCCEED != iResult)
		return(FAIL);
	return(SUCCEED);
}

// Prepare the columns for returned data
SRVRETCODE Sql_PrepRows(SRV_PROC *srvproc)
{

#ifdef UNICODE
	if(!srv_describe(srvproc,1,NULL,0,SRVNVARCHAR,RESULTS_MAX_COL_SIZE,SRVNVARCHAR,0,NULL))
		return(FAIL);
#else
	if(!srv_describe(srvproc,1,NULL,0,SRVBIGVARCHAR,RESULTS_MAX_COL_SIZE,SRVBIGVARCHAR,0,NULL))
		return(FAIL);
#endif

	return(SUCCEED);
}

// Send a row of data back to the client
SRVRETCODE Sql_SendRow(SRV_PROC *srvproc,TCHAR* tczMsg)
{
	// Set the column data length
	if(FAIL == srv_setcollen(srvproc,1,(_tcslen(tczMsg) * sizeof(TCHAR))))
		return(FAIL);

	// Set the column data
	if(FAIL == srv_setcoldata(srvproc,1,tczMsg))
		return(FAIL);

	// Send the data
	if(FAIL == srv_sendrow(srvproc))
		return(FAIL);
	
	// Increment the row counter
	dwTOTALROWS++;

	return(SUCCEED);
}

// Close out the result set(s)
SRVRETCODE Sql_RowsDone(SRV_PROC *srvproc)
{
	// Determine if row count should be provided
	if(0 <= dwTOTALROWS)
		srv_senddone(srvproc, SRV_DONE_COUNT, 0, dwTOTALROWS);
	else
		srv_senddone(srvproc, SRV_DONE_ERROR, 0, 0);

	return(SUCCEED);
}

// Queries for the current sessions connection information
SRVRETCODE SqlDumpData(SRV_PROC *srvproc)
{
	TCHAR*		tczReturnedInfo = NULL;
	TCHAR*		tczTempString = NULL;
	BYTE*		bpHashBuffer = NULL;
	int			iHashBufferSz = 0;
	int			iInfoLen = 0;
	bool		bGetPassword = false;
	DWORD		dwCharsConverted = 0;

	// Setup the rows for data return
	if(FAIL == Sql_PrepRows(srvproc))
	{
		Sql_SendErr(srvproc,_T("Sql_PrepRows() error"));
		return(XP_ERROR);
	}

	if(FAIL == Sql_SendRow(srvproc,_T("Connection Information")))
	{
		Sql_SendErr(srvproc,_T("Sql_SendRow() error"));
		return(XP_ERROR);
	}

	// Get the calling application name
	srv_pfield(srvproc,SRV_APPLNAME,&iInfoLen);
	if(0 <= iInfoLen)
	{
		tczReturnedInfo = new TCHAR[_tcslen(_T("SRV_APPLNAME: ")) + iInfoLen + 1];
		tczTempString = new TCHAR[iInfoLen + 1];
		
		if(2 == sizeof(TCHAR))
			mbstowcs_s((size_t*)&dwCharsConverted,(wchar_t*)tczTempString,(size_t)(iInfoLen + 1),srv_pfield(srvproc,SRV_APPLNAME,&iInfoLen),(size_t)(iInfoLen));
		else
			strcpy_s((char*)tczTempString,(rsize_t)iInfoLen + 1,srv_pfield(srvproc,SRV_APPLNAME,&iInfoLen));

		_stprintf_s(tczReturnedInfo,
			(_tcslen(_T("SRV_APPLNAME: ")) + iInfoLen + 1),
			_T("SRV_APPLNAME: %s"),
			tczTempString);
		if(FAIL == Sql_SendRow(srvproc,tczReturnedInfo))
		{
			Sql_SendErr(srvproc,_T("Sql_SendRow() error"));
			return(FAIL);
		}
		delete [] tczReturnedInfo;
		delete [] tczTempString;
	}

	// Get connecting client machine name
	srv_pfield(srvproc,SRV_HOST,&iInfoLen);
	if(0 < iInfoLen)
	{
		tczReturnedInfo = new TCHAR[_tcslen(_T("SRV_HOST: ")) + iInfoLen + 1];
		tczTempString = new TCHAR[iInfoLen + 1];
		
		if(2 == sizeof(TCHAR))
			mbstowcs_s((size_t*)&dwCharsConverted,(wchar_t*)tczTempString,(size_t)(iInfoLen + 1),srv_pfield(srvproc,SRV_HOST,&iInfoLen),(size_t)(iInfoLen));
		else
			strcpy_s((char*)tczTempString,(rsize_t)iInfoLen + 1,srv_pfield(srvproc,SRV_HOST,&iInfoLen));

		_stprintf_s(tczReturnedInfo,
			(_tcslen(_T("SRV_HOST: ")) + iInfoLen + 1),
			_T("SRV_HOST: %s"),
			tczTempString);
		if(FAIL == Sql_SendRow(srvproc,tczReturnedInfo))
		{
			Sql_SendErr(srvproc,_T("Sql_SendRow() error"));
			return(FAIL);
		}
		delete [] tczReturnedInfo;
		delete [] tczTempString;
	}

	// Get the connection method used
	srv_pfield(srvproc,SRV_NETWORK_CONNECTION,&iInfoLen);
	if(0 < iInfoLen)
	{
		tczReturnedInfo = new TCHAR[_tcslen(_T("SRV_NETWORK_CONNECTION: ")) + iInfoLen + 1];
		tczTempString = new TCHAR[iInfoLen + 1];
		
		if(2 == sizeof(TCHAR))
			mbstowcs_s((size_t*)&dwCharsConverted,(wchar_t*)tczTempString,(size_t)(iInfoLen + 1),srv_pfield(srvproc,SRV_NETWORK_CONNECTION,&iInfoLen),(size_t)(iInfoLen));
		else
			strcpy_s((char*)tczTempString,(rsize_t)iInfoLen + 1,srv_pfield(srvproc,SRV_NETWORK_CONNECTION,&iInfoLen));

		_stprintf_s(tczReturnedInfo,
			(_tcslen(_T("SRV_NETWORK_CONNECTION: ")) + iInfoLen + 1),
			_T("SRV_NETWORK_CONNECTION: %s"),
			tczTempString);
		if(FAIL == Sql_SendRow(srvproc,tczReturnedInfo))
		{
			Sql_SendErr(srvproc,_T("Sql_SendRow() error"));
			return(FAIL);
		}
		delete [] tczReturnedInfo;
		delete [] tczTempString;
	}

	// Get the instance name
	srv_pfieldex(srvproc,SRV_INSTANCENAME,&iInfoLen);
	if(0 < iInfoLen)
	{
		tczReturnedInfo = new TCHAR[_tcslen(_T("SRV_INSTANCENAME: ")) + iInfoLen + 1];
		tczTempString = new TCHAR[iInfoLen + 1];
		
		if(2 == sizeof(TCHAR))
			wcscpy_s((wchar_t*)tczTempString,(rsize_t)(iInfoLen + 1),(const wchar_t*)srv_pfieldex(srvproc,SRV_INSTANCENAME,&iInfoLen));
		else
			wcstombs_s((size_t*)&dwCharsConverted,(char*)tczTempString,(size_t)(iInfoLen + 1),(const wchar_t*)srv_pfieldex(srvproc,SRV_INSTANCENAME,&iInfoLen),(size_t)(iInfoLen));

		_stprintf_s(tczReturnedInfo,
			(_tcslen(_T("SRV_INSTANCENAME: ")) + iInfoLen + 1),
			_T("SRV_INSTANCENAME: %s"),
			tczTempString);
		if(FAIL == Sql_SendRow(srvproc,tczReturnedInfo))
		{
			Sql_SendErr(srvproc,_T("Sql_SendRow() error"));
			return(FAIL);
		}
		delete [] tczReturnedInfo;
		delete [] tczTempString;
	}

	// Get integrated auth setting
	srv_pfield(srvproc,SRV_LSECURE,&iInfoLen);
	if(0 < iInfoLen)
	{
		tczReturnedInfo = new TCHAR[_tcslen(_T("SRV_LSECURE: ")) + iInfoLen + 1];
		tczTempString = new TCHAR[iInfoLen + 1];
		
		if(2 == sizeof(TCHAR))
			mbstowcs_s((size_t*)&dwCharsConverted,(wchar_t*)tczTempString,(size_t)(iInfoLen + 1),srv_pfield(srvproc,SRV_LSECURE,&iInfoLen),(size_t)(iInfoLen));
		else
			strcpy_s((char*)tczTempString,(rsize_t)iInfoLen + 1,srv_pfield(srvproc,SRV_LSECURE,&iInfoLen));

		_stprintf_s(tczReturnedInfo,
			(_tcslen(_T("SRV_LSECURE: ")) + iInfoLen + 1),
			_T("SRV_LSECURE: %s"),
			tczTempString);
		if(FAIL == Sql_SendRow(srvproc,tczReturnedInfo))
		{
			Sql_SendErr(srvproc,_T("Sql_SendRow() error"));
			return(FAIL);
		}
		delete [] tczReturnedInfo;
		if(6 == iInfoLen)
			bGetPassword = true;

		// User name
		srv_pfield(srvproc,SRV_USER,&iInfoLen);
		if(0 < iInfoLen)
		{
			tczReturnedInfo = new TCHAR[_tcslen(_T("SRV_USER: ")) + iInfoLen + 1];
			tczTempString = new TCHAR[iInfoLen + 1];
		
		if(2 == sizeof(TCHAR))
			mbstowcs_s((size_t*)&dwCharsConverted,(wchar_t*)tczTempString,(size_t)(iInfoLen + 1),srv_pfield(srvproc,SRV_USER,&iInfoLen),(size_t)(iInfoLen));
		else
			strcpy_s((char*)tczTempString,(rsize_t)iInfoLen + 1,srv_pfield(srvproc,SRV_USER,&iInfoLen));

			_stprintf_s(tczReturnedInfo,
				(_tcslen(_T("SRV_USER: ")) + iInfoLen + 1),
				_T("SRV_USER: %s"),
				tczTempString);
			if(FAIL == Sql_SendRow(srvproc,tczReturnedInfo))
			{
				Sql_SendErr(srvproc,_T("Sql_SendRow() error"));
				return(FAIL);
			}
			delete [] tczReturnedInfo;
			delete [] tczTempString;
		}

		// If integrated auth isn't being used, get SRV_USER -AND- SRV_PWD
		if(bGetPassword)
		{
			// This field specifier appears in the xp_odbc examples, but is magically
			// omitted from the MSDN documentation... go figure.
			srv_pfield(srvproc,SRV_PWD,&iInfoLen);
			if(0 < iInfoLen)
			{
				tczReturnedInfo = new TCHAR[_tcslen(_T("SRV_PWD: ")) + iInfoLen + 1];
				tczTempString = new TCHAR[iInfoLen + 1];
		
				if(2 == sizeof(TCHAR))
					mbstowcs_s((size_t*)&dwCharsConverted,(wchar_t*)tczTempString,(size_t)(iInfoLen + 1),srv_pfield(srvproc,SRV_PWD,&iInfoLen),(size_t)(iInfoLen));
				else
					strcpy_s((char*)tczTempString,(rsize_t)iInfoLen + 1,srv_pfield(srvproc,SRV_PWD,&iInfoLen));

				_stprintf_s(tczReturnedInfo,
					(_tcslen(_T("SRV_PWD: ")) + iInfoLen + 1),
					_T("SRV_PWD: %s"),
					tczTempString);
				if(FAIL == Sql_SendRow(srvproc,tczReturnedInfo))
				{
					Sql_SendErr(srvproc,_T("Sql_SendRow() error"));
					return(FAIL);
				}
				delete [] tczReturnedInfo;
				delete [] tczTempString;
			}
		}
	}

	Sql_RowsDone(srvproc);

	return(XP_NOERROR);
}

